/*  For details see:
        http://developer.qt.nokia.com/wiki/Qt_thread-safe_singleton
 */
#ifndef __LEAQ_KERNEL_CALLONCE_HPP__
#define __LEAQ_KERNEL_CALLONCE_HPP__

#include <QtGlobal>
#include <QThread>
#include <QAtomicInt>
#include <QThreadStorage>

namespace LEAQ {
namespace Kernel {
namespace Internal {

namespace CallOnce {

enum ECallOnce {
    Request,
    InProgress,
    Finished
};

} // namespace CallOnce

template<class Function>
inline static void callOnce(
        Function function, QBasicAtomicInt& flag)
{
    int protectFlag = flag.fetchAndStoreAcquire(flag);

    if(protectFlag == CallOnce::Finished) {
        return;
    }

    if(protectFlag == CallOnce::Request
            && flag.testAndSetRelaxed(protectFlag, CallOnce::InProgress)) {

        function();
        flag.fetchAndStoreRelease(CallOnce::Finished);

    } else {

        do {
            QThread::yieldCurrentThread();
        } while (!flag.testAndSetAcquire(CallOnce::Finished, CallOnce::Finished));
    }
}

} // namespace Internal
} // namespace Kernel
} // namespace LEAQ

#endif // __LEAQ_KERNEL_CALLONCE_HPP__
